/** * This file is protected by Copyright. * Please refer to the COPYRIGHT file distributed with this source distribution. * * This file is part of REDHAWK IDE. * * All rights reserved. This program and the accompanying materials are made available under * the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html. * */ package gov.redhawk.ui.editor; import gov.redhawk.eclipsecorba.library.IdlLibrary; import gov.redhawk.eclipsecorba.library.util.RefreshIdlLibraryJob; import gov.redhawk.internal.ui.ScaIdeConstants; import gov.redhawk.internal.ui.editor.validation.ValidatingEContentAdapter; import gov.redhawk.ui.RedhawkUiActivator; import gov.redhawk.ui.util.ViewerUtil; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EventObject; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import mil.jpeojtrs.sca.util.CorbaUtils; import mil.jpeojtrs.sca.validator.AdvancedEObjectValidator; import org.eclipse.core.databinding.Binding; import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.databinding.observable.IObservable; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExecutableExtension; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.emf.common.command.BasicCommandStack; import org.eclipse.emf.common.command.Command; import org.eclipse.emf.common.command.CommandStack; import org.eclipse.emf.common.command.CommandStackListener; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.common.ui.dialogs.DiagnosticDialog; import org.eclipse.emf.common.ui.viewer.IViewerProvider; import org.eclipse.emf.common.util.BasicDiagnostic; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.databinding.EMFDataBindingContext; import org.eclipse.emf.databinding.edit.EditingDomainEObjectObservableValue; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EValidator; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.xmi.XMLResource; import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.emf.edit.domain.IEditingDomainProvider; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.emf.edit.provider.IDisposable; import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory; import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory; import org.eclipse.emf.edit.ui.dnd.EditingDomainViewerDropAdapter; import org.eclipse.emf.edit.ui.dnd.LocalTransfer; import org.eclipse.emf.edit.ui.dnd.ViewerDragAdapter; import org.eclipse.emf.edit.ui.provider.UnwrappingSelectionProvider; import org.eclipse.emf.edit.ui.util.EditUIUtil; import org.eclipse.emf.transaction.NotificationFilter; import org.eclipse.emf.transaction.Transaction; import org.eclipse.emf.transaction.TransactionalCommandStack; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl; import org.eclipse.emf.workspace.util.WorkspaceSynchronizer; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.databinding.swt.ISWTObservable; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentListener; import org.eclipse.jface.viewers.IPostSelectionProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CTabFolder; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.IStorageEditorInput; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.eclipse.ui.dialogs.SaveAsDialog; import org.eclipse.ui.editors.text.TextEditor; import org.eclipse.ui.forms.editor.FormEditor; import org.eclipse.ui.forms.editor.IFormPage; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.ide.IGotoMarker; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.part.MultiPageEditorPart; import org.eclipse.ui.part.MultiPageEditorSite; import org.eclipse.ui.progress.WorkbenchJob; import org.eclipse.ui.statushandlers.StatusManager; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; import org.xml.sax.InputSource; /** * The Class SCAFormEditor. */ public abstract class SCAFormEditor extends FormEditor implements IEditingDomainProvider, IMenuListener, IExecutableExtension, IViewerProvider, IGotoMarker { /** * @since 6.0 */ public static int getFieldBindingDelay() { return 200; } /** * Heavily inspired by code in the GEF LogicEditor example * * @since 6.0 */ public class ResourceTracker implements IResourceChangeListener, IResourceDeltaVisitor { private final Set<IResource> trackedResources; public ResourceTracker() { super(); this.trackedResources = new HashSet<IResource>(); } public ResourceTracker(final IResource[] loadedResources) { super(); this.trackedResources = new HashSet<IResource>(Arrays.asList(loadedResources)); } public void addTrackedResource(final IResource resource) { this.trackedResources.add(resource); } public void removeTrackedResource(final IResource resource) { this.trackedResources.remove(resource); } public void clearTrackedResources() { this.trackedResources.clear(); } @Override public void resourceChanged(final IResourceChangeEvent event) { final IResourceDelta delta = event.getDelta(); switch (event.getType()) { case IResourceChangeEvent.POST_CHANGE: case IResourceChangeEvent.PRE_CLOSE: case IResourceChangeEvent.PRE_DELETE: if (delta != null) { if (Display.getCurrent() == null) { PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { @Override public void run() { try { delta.accept(ResourceTracker.this); } catch (final CoreException e) { // PASS } } }); } else { try { delta.accept(this); } catch (final CoreException e) { // PASS } } } break; default: break; } } @Override public boolean visit(final IResourceDelta delta) throws CoreException { if (reloading) { return false; } if ((delta == null) || (!this.trackedResources.contains(delta.getResource()))) { return true; } switch (delta.getKind()) { case IResourceDelta.REMOVED: if ((IResourceDelta.MOVED_TO & delta.getFlags()) == 0) { // deleted final IFile resource = ResourcesPlugin.getWorkspace().getRoot().getFile(delta.getFullPath()); SCAFormEditor.this.resourceDeleted(resource); } else { // moved or renamed final IFile to = ResourcesPlugin.getWorkspace().getRoot().getFile(delta.getMovedToPath()); SCAFormEditor.this.resourceMoved(delta.getResource(), to); } break; case IResourceDelta.CHANGED: // Ignore changes if they are only to markers, or if the changes aren't for a file if (delta.getFlags() == IResourceDelta.MARKERS) { break; } if (!(delta.getResource() instanceof IFile)) { break; } final IFile newFile = (IFile) delta.getResource(); // If the resource has been changed on disk and the editor is dirty we will prompt the user before // blowing away its changes. if (SCAFormEditor.this.isDirty() && !SCAFormEditor.this.editorSaving) { boolean confirmOverwrite = MessageDialog.openConfirm(SCAFormEditor.this.getSite().getShell(), "File Changed", "The file '" + delta.getResource().getFullPath().toOSString() + "' has been changed on the file system. Do you want to replace the editor contents with these changes?"); SCAFormEditor.this.setFocus(); if (confirmOverwrite) { SCAFormEditor.this.resourceChanged(newFile, delta); // Since the document gets changed within the resourceChanged function, the document will be // marked dirty even though the document matches what is on disk. Currently I cannot figure out // a good way to get rid of this dirty flag. It's a small bug that should not happen often // though. } } // If the editor is not dirty and the editor is not in the middle of saving then we'll take the // changes. This will cause the editor to appear dirty erroneously as mentioned in the note above. if (!SCAFormEditor.this.isDirty() && !SCAFormEditor.this.editorSaving) { SCAFormEditor.this.resourceChanged(newFile, delta); } break; default: break; } return false; } } /** * @since 6.0 */ private ResourceTracker resourceTracker = new ResourceTracker(); private boolean reloading = false; /** * Updates the OutlinePage selection. */ public class SCAFormEditorChangeListener implements ISelectionChangedListener { /** * Installs this selection changed listener with the given selection provider. If the selection provider is a * post selection provider, post selection changed events are the preferred choice, otherwise normal selection * changed events are requested. * * @param selectionProvider the selection provider */ public void install(final ISelectionProvider selectionProvider) { if (selectionProvider == null) { return; } if (selectionProvider instanceof IPostSelectionProvider) { final IPostSelectionProvider provider = (IPostSelectionProvider) selectionProvider; provider.addPostSelectionChangedListener(this); } else { selectionProvider.addSelectionChangedListener(this); } } /** * {@inheritDoc} */ @Override public void selectionChanged(final SelectionChangedEvent event) { if (RedhawkUiActivator.getDefault().getPreferenceStore().getBoolean("ToggleLinkWithEditorAction.isChecked")) { if (getFormOutline() != null) { getFormOutline().setSelection(event.getSelection()); } } } /** * Removes this selection changed listener from the given selection provider. * * @param selectionProvider the selection provider */ public void uninstall(final ISelectionProvider selectionProvider) { if (selectionProvider == null) { return; } if (selectionProvider instanceof IPostSelectionProvider) { final IPostSelectionProvider provider = (IPostSelectionProvider) selectionProvider; provider.removePostSelectionChangedListener(this); } else { selectionProvider.removeSelectionChangedListener(this); } } } private static final String F_DIALOG_EDITOR_SECTION_KEY = "pde-form-editor"; //$NON-NLS-1$ private WorkbenchJob updateTitleJob; @Override protected void setSite(final org.eclipse.ui.IWorkbenchPartSite site) { this.updateTitleJob = new WorkbenchJob(site.getShell().getDisplay(), "UpdateTitle") { { setUser(false); setSystem(true); } @Override public IStatus runInUIThread(final IProgressMonitor monitor) { firePropertyChange(IWorkbenchPart.PROP_TITLE); return Status.OK_STATUS; } }; super.setSite(site); } /** * The editor selection changed listener. */ private SCAFormEditorChangeListener fEditorSelectionChangedListener; private Clipboard clipboard; private IContentOutlinePage fFormOutline; private SCAMultiPageContentOutline fContentOutline; private int fLastActivePageIndex; private boolean fLastDirtyState; private boolean handledStructuredModelChange; /** * Listen for changes to command stack and attempt to handle the change. */ private CommandStackListener commandStackListener = new CommandStackListener() { @Override public void commandStackChanged(final EventObject event) { if (Display.getCurrent() != null) { handleStackChanged(event); } else if (getContainer() != null && !getContainer().isDisposed()) { getContainer().getDisplay().asyncExec(new Runnable() { @Override public void run() { if (getContainer() != null && !getContainer().isDisposed()) { handleStackChanged(event); } } }); } } private void handleStackChanged(EventObject event) { handleStructuredModelChange(event); firePropertyChange(IEditorPart.PROP_DIRTY); final Command mostRecentCommand = ((CommandStack) event.getSource()).getMostRecentCommand(); if (mostRecentCommand != null && mostRecentCommand.getAffectedObjects() != null && !mostRecentCommand.getAffectedObjects().isEmpty()) { setSelectionToViewer(mostRecentCommand.getAffectedObjects()); } } }; /** * This keeps track of the editing domain that is used to track all changes to the model. */ private EditingDomain editingDomain; /** The outline cache. */ private final Map<IEditorPart, IContentOutlinePage> outlineCache = new HashMap<IEditorPart, IContentOutlinePage>(); private final DataBindingContext bindingContext; private ValidatingEContentAdapter validator; private String id; private boolean disposed; private Resource mainResource; private final Map<Resource, IDocument> resourceToDocumentMap = new HashMap<Resource, IDocument>(); /** * @since 8.0 */ protected boolean editorSaving; private RefreshIdlLibraryJob reloadLibraryJob; /** * The Class SCAMultiPageEditorSite. */ private static class SCAMultiPageEditorSite extends MultiPageEditorSite { /** * Instantiates a new sCA multi page editor site. * * @param multiPageEditor the multi page editor * @param editor the editor */ public SCAMultiPageEditorSite(final MultiPageEditorPart multiPageEditor, final IEditorPart editor) { super(multiPageEditor, editor); } /** * {@inheritDoc} */ @Override public IWorkbenchPart getPart() { return getMultiPageEditor(); } @Override protected void handleSelectionChanged(SelectionChangedEvent event) { // On occasion, viewers that are not visible may still emit selection change events due to model updates // (mostly StructuredTextEditors); from the perspective of the form editor, these selection events should // be ignored, otherwise the properties view may unexpectedly change contents. if (isSelectionSourceVisible(event)) { super.handleSelectionChanged(event); } } @Override protected void handlePostSelectionChanged(SelectionChangedEvent event) { // See above. if (isSelectionSourceVisible(event)) { super.handlePostSelectionChanged(event); } } private boolean isSelectionSourceVisible(SelectionChangedEvent event) { if (event.getSource() instanceof Viewer) { Viewer viewer = (Viewer) event.getSource(); Control control = viewer.getControl(); if (!control.isVisible()) { return false; } } return true; } } /** * Instantiates a new sCA form editor. */ public SCAFormEditor() { this.bindingContext = new EMFDataBindingContext(); } /** * Handles activation of the editor or it's associated views. */ protected void handleActivate() { // Recompute the read only state. // if (this.editingDomain instanceof AdapterFactoryEditingDomain) { if (((AdapterFactoryEditingDomain) this.editingDomain).getResourceToReadOnlyMap() != null) { ((AdapterFactoryEditingDomain) this.editingDomain).getResourceToReadOnlyMap().clear(); // Refresh any actions that may become enabled or disabled. // getSite().getSelectionProvider().setSelection(getSite().getSelectionProvider().getSelection()); } } } /** * This sets up the editing domain for the model editor. */ protected void initializeEditingDomain() { TransactionalEditingDomain domain = createEditingDomain(); final Map<String, Boolean> myOptions = new HashMap<String, Boolean>(); myOptions.put(Transaction.OPTION_NO_VALIDATION, Boolean.TRUE); if (domain instanceof TransactionalEditingDomainImpl) { ((TransactionalEditingDomainImpl) domain).setDefaultTransactionOptions(myOptions); } final NotificationFilter resourceModifiedFilter = NotificationFilter.createNotifierFilter(domain.getResourceSet()).and( NotificationFilter.createEventTypeFilter(Notification.ADD)).and( NotificationFilter.createFeatureFilter(ResourceSet.class, ResourceSet.RESOURCE_SET__RESOURCES)); domain.getResourceSet().eAdapters().add(new Adapter() { private Notifier myTarget; @Override public Notifier getTarget() { return this.myTarget; } @Override public boolean isAdapterForType(final Object type) { return false; } @Override public void notifyChanged(final Notification notification) { if (resourceModifiedFilter.matches(notification)) { final Object value = notification.getNewValue(); if (value instanceof Resource) { ((Resource) value).setTrackingModification(true); } } } @Override public void setTarget(final Notifier newTarget) { this.myTarget = newTarget; } }); // Add a listener to set the most recent command's affected objects to // be the selection of the viewer with focus. // domain.getCommandStack().addCommandStackListener(this.commandStackListener); this.editingDomain = domain; } /** * @since 8.0 */ protected TransactionalEditingDomain createEditingDomain() { TransactionalEditingDomain domain = TransactionalEditingDomain.Registry.INSTANCE.getEditingDomain(getEditingDomainId()); if (domain == null) { domain = TransactionalEditingDomain.Factory.INSTANCE.createEditingDomain(); domain.setID(getEditingDomainId()); // Create an adapter factory that yields item providers. // final ComposedAdapterFactory localAdapterFactory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE); localAdapterFactory.addAdapterFactory(new ResourceItemProviderAdapterFactory()); localAdapterFactory.addAdapterFactory(getSpecificAdapterFactory()); localAdapterFactory.addAdapterFactory(new ReflectiveItemProviderAdapterFactory()); ((AdapterFactoryEditingDomain) domain).setAdapterFactory(localAdapterFactory); } return domain; } /** * Provide access to the command stack listener so that subclasses may remove if so desired. * * @return the {@link CommandStackListener} associated with this editors editing domain * @since 4.0 */ protected CommandStackListener getCommandStackListener() { return this.commandStackListener; } /** * @return The ID of the Editing Domain used by this editor */ public abstract String getEditingDomainId(); /** * @return Adapter Factory Specific to this editor */ protected abstract AdapterFactory getSpecificAdapterFactory(); /** * We must override nested site creation so that we properly pass the source editor contributor when asked. * * @param editor the editor * @return the i editor site */ @Override protected IEditorSite createSite(final IEditorPart editor) { return new SCAMultiPageEditorSite(this, editor); } /** * Gets the context manager. * * @return the context manager */ @Override public EditingDomain getEditingDomain() { return this.editingDomain; } /** * {@inheritDoc} */ @Override protected FormToolkit createToolkit(final Display display) { // Create a toolkit that shares colors between editors. return new FormToolkit(RedhawkUiActivator.getDefault().getFormColors(display)); } /* * When subclassed, don't forget to call 'super' */ /** * {@inheritDoc} */ @Override protected void createPages() { this.clipboard = new Clipboard(getContainer().getDisplay()); super.createPages(); final int pageIndex = computeInitialPageId(); if (pageIndex >= 0 && pageIndex < getPageCount()) { setActivePage(pageIndex); } updateTitle(); final Notifier obj = getRootValidationNotifier(); this.validator = new ValidatingEContentAdapter(this, obj); if (obj != null) { obj.eAdapters().add(this.validator); this.validate(); } // Ensures that this editor will only display the page's tab // area if there are more than one page // getContainer().addControlListener(new ControlAdapter() { private boolean guard = false; @Override public void controlResized(final ControlEvent event) { if (!this.guard) { this.guard = true; hideTabs(); this.guard = false; } } }); } /** * @return */ protected Notifier getRootValidationNotifier() { return this.getMainResource(); } /** * If there is just one page in the multi-page editor part, this hides the single tab at the bottom. <!-- * begin-user-doc --> <!-- end-user-doc --> */ protected void hideTabs() { if (getPageCount() == 1) { setPageText(0, ""); if (getContainer() instanceof CTabFolder) { ((CTabFolder) getContainer()).setTabHeight(1); final Point point = getContainer().getSize(); getContainer().setSize(point.x, point.y + 6); // SUPPRESS CHECKSTYLE MagicNumber } } } /** * If there is more than one page in the multi-page editor part, this shows the tabs at the bottom. <!-- * begin-user-doc --> <!-- end-user-doc --> * * @generated */ protected void showTabs() { if (getPageCount() > 1) { if (getContainer() instanceof CTabFolder) { ((CTabFolder) getContainer()).setTabHeight(SWT.DEFAULT); final Point point = getContainer().getSize(); getContainer().setSize(point.x, point.y - 6); // SUPPRESS CHECKSTYLE MagicNumber } } } /** * {@inheritDoc} */ @Override protected void pageChange(final int newPageIndex) { super.pageChange(newPageIndex); updateContentOutline(newPageIndex); this.fLastActivePageIndex = newPageIndex; final Viewer viewer = getViewer(); if (viewer != null) { this.setSelection(viewer.getSelection()); } else { this.setSelection(new StructuredSelection()); } validate(); } /** * {@inheritDoc} */ @Override public void setFocus() { super.setFocus(); final IFormPage page = getActivePageInstance(); // Could be done on setActive in PDEFormPage; // but setActive only handles page switches and not focus events if ((page != null) && (page instanceof ScaFormPage)) { ((ScaFormPage) page).updateFormSelection(); } } /** * Gets the clipboard. * * @return the clipboard * @since 5.0 */ public Clipboard getClipboard() { return this.clipboard; } /** * Gets the contributor. * * @return the contributor */ public ScaMultipageActionBarContributor getActionBarContributor() { return (ScaMultipageActionBarContributor) getEditorSite().getActionBarContributor(); } /** * Compute initial page id. * * @return the string */ protected int computeInitialPageId() { int firstPageId = 0; final String storedFirstPageId = loadDefaultPage(); if (storedFirstPageId != null) { try { firstPageId = Integer.valueOf(storedFirstPageId); } catch (final NumberFormatException e) { firstPageId = 0; } } if (firstPageId >= getPageCount()) { firstPageId = 0; } return firstPageId; } /** * Update title. */ public void updateTitle() { this.updateTitleJob.schedule(); } /** * Gets the title property. * * @return the title property */ public String getTitleProperty() { return ""; //$NON-NLS-1$ } /** * {@inheritDoc} */ @Override public void doSave(final IProgressMonitor monitor) { try { this.editorSaving = true; commitPages(true); monitor.beginTask("Saving " + this.getTitle(), this.getPageCount() + 2); internalDoValidate(new SubProgressMonitor(monitor, 1)); for (int i = 0; i < this.getPageCount(); i++) { final IEditorPart part = this.getEditor(i); if (part != null && part.isDirty()) { part.doSave(new SubProgressMonitor(monitor, 1)); } else { monitor.worked(1); } } if (isDirty()) { emfDoSave(new SubProgressMonitor(monitor, 1)); } editorDirtyStateChanged(); } catch (final OperationCanceledException e) { // PASS } finally { monitor.done(); this.editorSaving = false; } } /** * @since 6.0 */ protected void closeEditor(final boolean save) { getSite().getPage().closeEditor(this, save); } /** * This is for implementing {@link IEditorPart} and simply saves the model file. * * @param progressMonitor the progress monitor * @since 2.3 */ protected void emfDoSave(final IProgressMonitor progressMonitor) { // Save only resources that have actually changed. // final Map<Object, Object> saveOptions = new HashMap<Object, Object>(); saveOptions.put(Resource.OPTION_SAVE_ONLY_IF_CHANGED, Resource.OPTION_SAVE_ONLY_IF_CHANGED_MEMORY_BUFFER); // Do the work within an operation because this is a long running // activity that modifies the workbench. // final WorkspaceModifyOperation operation = new WorkspaceModifyOperation() { // This is the method that gets invoked when the operation runs. // @Override public void execute(final IProgressMonitor monitor) throws CoreException { // Save the resources to the file system. // for (final Resource resource : SCAFormEditor.this.editingDomain.getResourceSet().getResources()) { if (isPersisted(resource) && !SCAFormEditor.this.editingDomain.isReadOnly(resource)) { // Lastly, check to make sure this resource is not only local to the current workspace // but is also local to the project we're currently saving. This fixes bug # 266 if (isPersisted(resource) && isLocal(resource)) { try { resource.save(saveOptions); } catch (final Exception exception) { // SUPPRESS CHECKSTYLE Logged Catch all exception throw new CoreException(new Status(IStatus.ERROR, RedhawkUiActivator.getPluginId(), "Failed to save resource: " + resource, exception)); } } } } } /** * Checks to see if the given resource is within the same project as the SCAFormEditor. * This fixes bug # 266 * @param resource The resource to be checked * @return */ private boolean isLocal(final Resource resource) { // If the resource isn't located in the workspace it isn't local if (!resource.getURI().isPlatformResource()) { return false; } // Get the file for the referenced resource IPath pathToResource = new Path(resource.getURI().toPlatformString(true)); IFile resourceFile = ResourcesPlugin.getWorkspace().getRoot().getFile(pathToResource); // Check the file's project against the SCA Form Editor's scd file's project. if (resourceFile != null && resourceFile.getProject() != null) { if (SCAFormEditor.this.getEditorInput() instanceof IFileEditorInput) { IFile localFile = ((IFileEditorInput) SCAFormEditor.this.getEditorInput()).getFile(); if (localFile != null) { if (localFile.getProject().equals(resourceFile.getProject())) { return true; } } } } return false; } }; try { operation.run(progressMonitor); // Refresh the necessary state. // ((BasicCommandStack) this.editingDomain.getCommandStack()).saveIsDone(); } catch (final Exception exception) { // SUPPRESS CHECKSTYLE Logged Catch all exception // Something went wrong that shouldn't. // StatusManager.getManager().handle( new Status(IStatus.ERROR, RedhawkUiActivator.getPluginId(), "Error occured while attempting to save.", exception), StatusManager.SHOW | StatusManager.LOG); } } /** * This returns whether something has been persisted to the URI of the specified resource. The implementation uses * the URI converter from the editor's resource set to try to open an input stream. * * @param resource the resource * @return true, if checks if is persisted * @since 2.1 */ public boolean isPersisted(final Resource resource) { // If the resource isn't located in the workspace it isn't local if (resource != null && resource.getURI() != null && resource.getURI().isPlatformResource()) { // Get the file for the referenced resource IPath pathToResource = new Path(resource.getURI().toPlatformString(true)); IFile resourceFile = ResourcesPlugin.getWorkspace().getRoot().getFile(pathToResource); // Check the file's project against the SCA Form Editor's scd file's project. if (resourceFile != null && resourceFile.getProject() != null) { if (SCAFormEditor.this.getEditorInput() instanceof IFileEditorInput) { IFile localFile = ((IFileEditorInput) SCAFormEditor.this.getEditorInput()).getFile(); if (localFile != null) { if (localFile.getProject().equals(resourceFile.getProject())) { return true; } } } } return false; } return false; } /** * {@inheritDoc} */ @Override public void gotoMarker(final IMarker marker) { final String uriAttribute = marker.getAttribute(EValidator.URI_ATTRIBUTE, null); final int featureID = marker.getAttribute(AdvancedEObjectValidator.FEATURE_ID, AdvancedEObjectValidator.DEFAULT_ID); if (uriAttribute != null) { final URI uri = URI.createURI(uriAttribute); final EObject eObject = this.editingDomain.getResourceSet().getEObject(uri, true); if (eObject != null) { for (final Object o : this.bindingContext.getBindings()) { final Binding binding = (Binding) o; EditingDomainEObjectObservableValue emfObservable = null; ISWTObservable swtObservable = null; final IObservable model = binding.getModel(); final IObservable target = binding.getTarget(); if (model instanceof EditingDomainEObjectObservableValue && target instanceof ISWTObservable) { emfObservable = (EditingDomainEObjectObservableValue) model; swtObservable = (ISWTObservable) target; } else if (binding.getTarget() instanceof EditingDomainEObjectObservableValue && model instanceof ISWTObservable) { swtObservable = (ISWTObservable) model; emfObservable = (EditingDomainEObjectObservableValue) target; } if (emfObservable != null && swtObservable != null) { if (this.selectFeature(emfObservable, swtObservable, eObject, featureID)) { break; } } } } } } /** * Sets focus on the correct control. * * @param emfObservable * @param swtObservable * @param object * @param featureID * @return */ private boolean selectFeature(final EditingDomainEObjectObservableValue emfObservable, final ISWTObservable swtObservable, final EObject object, final int featureID) { boolean retVal = false; final Object observed = emfObservable.getObserved(); if (emfObservable.getValueType() instanceof EStructuralFeature) { final int myId = ((EStructuralFeature) emfObservable.getValueType()).getFeatureID(); if (object == observed) { if (featureID == myId) { if (swtObservable.getWidget() instanceof Control) { final Control control = (Control) swtObservable.getWidget(); control.setFocus(); retVal = true; } } } } return retVal; } /** * This is the method called to load a resource into the editing domain's resource set based on the editor's input. */ protected void createModel() { final URI resourceURI = EditUIUtil.getURI(getEditorInput()); // For safety we'll decode the URI to make sure escape sequences have been correctly represented String decodedURIString = URI.decode(resourceURI.toString()); final URI decodedURI = URI.createURI(decodedURIString); Exception exception = null; try { // Load the resource through the editing domain. // if (Display.getCurrent() != null) { ProgressMonitorDialog dialog = new ProgressMonitorDialog(Display.getCurrent().getActiveShell()); dialog.run(true, true, new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { monitor.beginTask("Loading XML...", IProgressMonitor.UNKNOWN); mainResource = CorbaUtils.invoke(new Callable<Resource>() { @Override public Resource call() throws Exception { return editingDomain.getResourceSet().getResource(decodedURI, true); } }, monitor); } catch (CoreException e) { throw new InvocationTargetException(e); } } }); } else { mainResource = editingDomain.getResourceSet().getResource(decodedURI, true); } } catch (final Exception e) { // SUPPRESS CHECKSTYLE Logged Catch all exception exception = e; this.mainResource = this.editingDomain.getResourceSet().getResource(decodedURI, false); } if (exception != null) { StatusManager.getManager().handle( new Status(IStatus.ERROR, RedhawkUiActivator.getPluginId(), "Errors occured while loading the main resource of the editor.", exception), StatusManager.SHOW | StatusManager.LOG); } } /** * @return the mainResource */ public Resource getMainResource() { return this.mainResource; } /** * This also changes the editor's input. */ @Override public void doSaveAs() { if (!isSaveAsAllowed()) { throw new UnsupportedOperationException("Save as not supported"); } final SaveAsDialog saveAsDialog = new SaveAsDialog(getSite().getShell()); saveAsDialog.open(); final IPath path = saveAsDialog.getResult(); if (path != null) { final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path); if (file != null) { doSaveAs(URI.createPlatformResourceURI(file.getFullPath().toString(), true), new FileEditorInput(file)); } } } /** * Do save as. This method should be overridden. * * @param createPlatformResourceURI the create platform resource uri * @param fileEditorInput the file editor input * @since 5.0 */ protected void doSaveAs(final URI createPlatformResourceURI, final FileEditorInput fileEditorInput) { throw new UnsupportedOperationException("Save as not supported"); } /** * {@inheritDoc} */ @Override public boolean isSaveAsAllowed() { return false; } /** * */ private void storeDefaultPage() { final IEditorInput input = getEditorInput(); final String pageId = Integer.toString(this.fLastActivePageIndex); if (pageId == null) { return; } if (input instanceof IFileEditorInput) { // Triggered by opening a file in the workspace // e.g. From the Package Explorer View setPropertyEditorPageKey((IFileEditorInput) input, pageId); } else if (input instanceof IStorageEditorInput) { // Triggered by opening a file NOT in the workspace // e.g. From the Plug-in View setDialogEditorPageKey(pageId); } } /** * Sets the dialog editor page key. * * @param pageID the page id */ protected void setDialogEditorPageKey(final String pageID) { // Use one global setting for all files belonging to a given editor // type. Use the editor ID as the key. // Could use the storage editor input to get the underlying file // and use it as a unique key; but, the dialog settings file will // grow out of control and we do not need that level of granularity final IDialogSettings section = getSettingsSection(); section.put(getEditorID(), pageID); } /** * Gets the dialog editor page key. * * @return the dialog editor page key */ protected String getDialogEditorPageKey() { // Use one global setting for all files belonging to a given editor // type. Use the editor ID as the key. // Could use the storage editor input to get the underlying file // and use it as a unique key; but, the dialog settings file will // grow out of control and we do not need that level of granularity final IDialogSettings section = getSettingsSection(); return section.get(getEditorID()); } /** * Gets the editor id. * * @return the editor id */ protected final String getEditorID() { return this.id; } /** * Sets the property editor page key. * * @param input the input * @param pageId the page id * @since 5.0 */ protected void setPropertyEditorPageKey(final IFileEditorInput input, final String pageId) { // We are using the file itself to persist the editor page key property // The value persists even after the editor is closed final IFile file = input.getFile(); try { // Set the editor page ID as a persistent property on the file file.setPersistentProperty(ScaIdeConstants.PROPERTY_EDITOR_PAGE_KEY, pageId); } catch (final CoreException e) { // PASS } } /** * Load default page. * * @return the string */ private String loadDefaultPage() { final IEditorInput input = getEditorInput(); if (input instanceof IFileEditorInput) { // Triggered by opening a file in the workspace // e.g. From the Package Explorer View return getPropertyEditorPageKey((IFileEditorInput) input); } else if (input instanceof IStorageEditorInput) { // Triggered by opening a file NOT in the workspace // e.g. From the Plug-in View return getDialogEditorPageKey(); } return getDefaultPageKey(); } /** * @since 8.0 */ protected String getDefaultPageKey() { return null; } /** * Gets the property editor page key. * * @param input the input * @return the property editor page key * @since 5.0 */ protected String getPropertyEditorPageKey(final IFileEditorInput input) { // We are using the file itself to persist the editor page key property // The value persists even after the editor is closed final IFile file = input.getFile(); // Get the persistent editor page key from the file try { return file.getPersistentProperty(ScaIdeConstants.PROPERTY_EDITOR_PAGE_KEY); } catch (final CoreException e) { return null; } } /** * {@inheritDoc} */ @Override public void dispose() { this.disposed = true; storeDefaultPage(); if (this.fEditorSelectionChangedListener != null) { this.fEditorSelectionChangedListener.uninstall(getSite().getSelectionProvider()); this.fEditorSelectionChangedListener = null; } setSelection(new StructuredSelection()); if (this.clipboard != null) { this.clipboard.dispose(); this.clipboard = null; } if (getEditingDomain() instanceof AdapterFactoryEditingDomain) { if (((AdapterFactoryEditingDomain) this.editingDomain).getAdapterFactory() instanceof IDisposable) { ((IDisposable) ((AdapterFactoryEditingDomain) this.editingDomain).getAdapterFactory()).dispose(); } } if (this.commandStackListener != null) { if (this.editingDomain != null) { if (this.editingDomain.getCommandStack() != null) { this.editingDomain.getCommandStack().removeCommandStackListener(this.commandStackListener); } } this.commandStackListener = null; } this.editingDomain = null; this.outlineCache.clear(); // Waveform Explorer editor input is ScaFileStoreEditorInput, ignore this if (getEditorInput() instanceof IFileEditorInput) { final IFile file = ((IFileEditorInput) getEditorInput()).getFile(); file.getWorkspace().removeResourceChangeListener(this.resourceTracker); } if (this.resourceTracker != null) { this.resourceTracker.clearTrackedResources(); this.resourceTracker = null; } super.dispose(); } /** * {@inheritDoc} */ @Override public boolean isDirty() { this.fLastDirtyState = computeDirtyState(); return this.fLastDirtyState; } /** * Compute dirty state. * * @return true, if successful * @since 8.0 */ protected boolean computeDirtyState() { if ((this.editingDomain != null) && ((BasicCommandStack) this.editingDomain.getCommandStack()).isSaveNeeded()) { return true; } if (this.editingDomain != null) { return super.isDirty(); } return false; } /** * Gets the last dirty state. * * @return the last dirty state */ public boolean getLastDirtyState() { return this.fLastDirtyState; } /** * Gets the settings section. * * @return the settings section */ private IDialogSettings getSettingsSection() { // Store global settings that will persist when the editor is closed // in the dialog settings (This is cheating) // Get the dialog settings final IDialogSettings root = RedhawkUiActivator.getDefault().getDialogSettings(); // Get the dialog section reserved for PDE form editors IDialogSettings section = root.getSection(SCAFormEditor.F_DIALOG_EDITOR_SECTION_KEY); // If the section is not defined, define it if (section == null) { section = root.addNewSection(SCAFormEditor.F_DIALOG_EDITOR_SECTION_KEY); } return section; } /** * Sets the selection. * * @param selection the new selection */ public void setSelection(final ISelection selection) { if (getSite() != null && getSite().getSelectionProvider() != null) { getSite().getSelectionProvider().setSelection(selection); } } /** * Gets the selection. * * @return the selection */ public ISelection getSelection() { return getSite().getSelectionProvider().getSelection(); } /** * {@inheritDoc} */ @Override public <T> T getAdapter(final Class<T> key) { if (key.equals(IContentOutlinePage.class)) { return key.cast(getContentOutline()); } if (key.equals(IGotoMarker.class)) { return key.cast(this); } return super.getAdapter(key); } /** * Gets the content outline. * * @return the content outline */ public SCAMultiPageContentOutline getContentOutline() { if (this.fContentOutline == null || this.fContentOutline.isDisposed()) { this.fContentOutline = new SCAMultiPageContentOutline(this); updateContentOutline(getActivePage()); } return this.fContentOutline; } /** * Gets the form outline. * * @return outline page or null * @since 6.0 */ public IContentOutlinePage getFormOutline() { if (this.fFormOutline == null) { this.fFormOutline = createContentOutline(); if (this.fFormOutline != null) { this.fEditorSelectionChangedListener = new SCAFormEditorChangeListener(); this.fEditorSelectionChangedListener.install(getSite().getSelectionProvider()); } } return this.fFormOutline; } /** * Creates the content outline. * * @return the i sortable content outline page */ protected abstract IContentOutlinePage createContentOutline(); /** * Update content outline. * * @param index the index */ private void updateContentOutline(final int index) { if (this.fContentOutline == null) { return; } IContentOutlinePage outline = null; final IEditorPart editor = this.getEditor(index); if (editor != null) { outline = this.outlineCache.get(editor); if (outline == null) { final Object adapter = editor.getAdapter(IContentOutlinePage.class); if (adapter instanceof IContentOutlinePage) { outline = (IContentOutlinePage) adapter; this.outlineCache.put(editor, outline); } } } if (outline == null) { outline = getFormOutline(); if (outline != null && outline instanceof FormOutlinePage) { ((FormOutlinePage) outline).refresh(); } } this.fContentOutline.setPageActive(outline); } /** * {@inheritDoc} */ @Override public IFormPage setActivePage(final String pageId) { final IFormPage page = super.setActivePage(pageId); if (page != null) { updateContentOutline(page.getIndex()); } return page; } /** * {@inheritDoc} */ @Override public void init(final IEditorSite site, final IEditorInput input) throws PartInitException { super.init(site, input); // ResourcesPlugin.getWorkspace().addResourceChangeListener(this.resourceChangeListener, // IResourceChangeEvent.POST_CHANGE); } @Override protected void addPages() { // TODO Auto-generated method stub } /** * Add resource tracking to the provided input. Sub-classes may override but should call super.setInput(). * Sub-classes may add other resources to track via the getResourceTracker().addTrackedResource() */ @Override protected void setInput(final IEditorInput input) { IFile file = null; if (input instanceof IFileEditorInput) { file = ((IFileEditorInput) input).getFile(); } IFile previousFile = null; if ((getEditorInput() != null) && (getEditorInput() instanceof IFileEditorInput)) { previousFile = ((IFileEditorInput) getEditorInput()).getFile(); } // Remove the previous tracker...not technically necessary but // implemented for the sake of completeness if (previousFile != null) { this.resourceTracker.clearTrackedResources(); previousFile.getWorkspace().removeResourceChangeListener(this.resourceTracker); } initializeEditingDomain(); super.setInput(input); createModel(); if (file != null) { this.resourceTracker.addTrackedResource(file); file.getWorkspace().addResourceChangeListener(this.resourceTracker); } } /** * Contribute to toolbar. * * @param manager the manager */ public void contributeToToolbar(final IToolBarManager manager) { } /** * This creates a context menu for the viewer and adds a listener as well registering the menu for extension. * * @param viewer the viewer */ protected void createContextMenuFor(final StructuredViewer viewer) { final MenuManager contextMenu = new MenuManager("#PopUp"); contextMenu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); contextMenu.setRemoveAllWhenShown(true); contextMenu.addMenuListener(this); final Menu menu = contextMenu.createContextMenu(viewer.getControl()); viewer.getControl().setMenu(menu); getSite().registerContextMenu(contextMenu, new UnwrappingSelectionProvider(viewer)); final int dndOperations = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK; final Transfer[] transfers = new Transfer[] { LocalTransfer.getInstance() }; viewer.addDragSupport(dndOperations, transfers, new ViewerDragAdapter(viewer)); viewer.addDropSupport(dndOperations, transfers, new EditingDomainViewerDropAdapter(getEditingDomain(), viewer)); } /** * This implements {@link org.eclipse.jface.action.IMenuListener} to help fill the context menus with contributions * from the Edit menu. * * @param menuManager the menu manager */ @Override public void menuAboutToShow(final IMenuManager menuManager) { ((IMenuListener) getEditorSite().getActionBarContributor()).menuAboutToShow(menuManager); } /** * {@inheritDoc} */ @Override public void setInitializationData(final IConfigurationElement config, final String propertyName, final Object data) { super.setInitializationData(config, propertyName, data); this.id = config.getAttribute("id"); } /** * @return */ public DataBindingContext getDataBindingContext() { return this.bindingContext; } /** * @return */ public AdapterFactory getAdapterFactory() { if (getEditingDomain() instanceof AdapterFactoryEditingDomain) { return ((AdapterFactoryEditingDomain) getEditingDomain()).getAdapterFactory(); } return null; } /** * @since 8.0 */ public void validate() { validate(null); } /** * @since 8.0 */ public void validate(JobChangeAdapter adapter) { if (this.validator != null) { Display display = null; if (getSite() != null) { display = getSite().getShell().getDisplay(); } final WorkbenchJob job = new WorkbenchJob(display, "Validating editor: " + this.getTitle()) { @Override public boolean shouldRun() { return super.shouldRun() && !isDisposed(); } @Override public IStatus runInUIThread(final IProgressMonitor monitor) { SCAFormEditor.this.validator.validate(); final Viewer viewer = getViewer(); if (viewer != null) { viewer.refresh(); } return Status.OK_STATUS; } }; job.setSystem(true); job.setUser(false); // Validation Job should be DECORATE Priority; schedule for future to allow resource reload to complete. job.setPriority(Job.DECORATE); if (adapter != null) { job.addJobChangeListener(adapter); } job.schedule(); } } /** * @param monitor */ protected void internalDoValidate(final IProgressMonitor monitor) { // result of the Validation final BasicDiagnostic diagnostic = new BasicDiagnostic(); final List<Resource> resources = new ArrayList<Resource>(); resources.addAll(getEditingDomain().getResourceSet().getResources()); for (final Resource resource : resources) { if (isPersisted(resource)) { for (final EObject obj : resource.getContents()) { this.validator.validate(obj, diagnostic); } } } if (diagnostic.getSeverity() == Diagnostic.ERROR) { final Dialog dialog = new DiagnosticDialog(getSite().getShell(), "Invalid Model", null, diagnostic, Diagnostic.ERROR | Diagnostic.WARNING) { @Override protected Control createMessageArea(final Composite composite) { this.message = "Errors have been detected. Do you want to save anyway?"; return super.createMessageArea(composite); } @Override protected void createButtonsForButtonBar(final Composite parent) { // create OK and Details buttons createButton(parent, IDialogConstants.OK_ID, IDialogConstants.YES_LABEL, true); createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.NO_LABEL, true); createDetailsButton(parent); } }; if (dialog.open() != Window.OK) { if (monitor != null) { monitor.setCanceled(true); } throw new OperationCanceledException(); } } } /** * @return */ public boolean isDisposed() { return this.disposed; } /** * {@inheritDoc} */ @Override public Viewer getViewer() { final IFormPage page = this.getActivePageInstance(); if (page instanceof IViewerProvider) { return ((IViewerProvider) page).getViewer(); } return null; } @Override public int addPage(final IFormPage page) throws PartInitException { return super.addPage(page); }; /** * @since 6.0 */ public TextEditor createTextEditor(final IEditorInput input) { try { return new org.eclipse.wst.sse.ui.StructuredTextEditor(); } catch (final NoClassDefFoundError e) { return new TextEditor(); } } /** * Adds a complete editor part to the multi-page editor and associates an editor document with a resource; adds a * document listener to allow document changes to be propagated to the resource. * * @param editor the nested editor * @param input the input of the nested editor * @param resource the resource to associate with the editor * @return the index of the page in the editor * @throws PartInitException * @since 4.0 */ public int addPage(final IEditorPart editor, final IEditorInput input, final Resource resource) throws PartInitException { return addPage(-1, editor, input, resource); } /** * Adds a complete editor part to the multi-page editor and associates an editor document with a resource; adds a * document listener to allow document changes to be propagated to the resource. * * @param editor the nested editor * @param input the input of the nested editor * @param resource the resource to associate with the editor * @return the index of the page in the editor * @throws PartInitException * @since 6.0 */ public int addPage(int index, final IEditorPart editor, final IEditorInput input, final Resource resource) throws PartInitException { if (index == -1) { index = super.addPage(editor, input); } else { super.addPage(index, editor, input); } if (editor instanceof TextEditor) { final IDocument document = ((TextEditor) editor).getDocumentProvider().getDocument(editor.getEditorInput()); this.resourceToDocumentMap.put(resource, document); document.addDocumentListener(new IDocumentListener() { @Override public void documentAboutToBeChanged(final DocumentEvent documentEvent) { // Ignore } @Override public void documentChanged(final DocumentEvent documentEvent) { try { if (SCAFormEditor.this.handledStructuredModelChange) { SCAFormEditor.this.handledStructuredModelChange = false; } else { handleDocumentChange(resource); } } catch (final Exception exception) { // SUPPRESS CHECKSTYLE Fallback // PASS } } }); } return index; } /** * Updates a {@link Resource} with changes to its associated document. * * @param document the document that changed * @since 4.0 */ protected void handleDocumentChange(final Resource resource) { final IDocument document = this.resourceToDocumentMap.get(resource); final XMLResource xmlResource = (XMLResource) resource; try { if (xmlResource.isLoaded()) { xmlResource.unload(); } xmlResource.load(new InputSource(new StringReader(document.get())), xmlResource.getDefaultLoadOptions()); } catch (final Exception exception) { // SUPPRESS CHECKSTYLE Fallback // PASS - Allow the validators to do their job rather than prevent invalid xml } } /** * Updates each document associated with this editor based on its associated {@link Resource} changes. * * @since 4.0 */ protected void handleStructuredModelChange(final EventObject event) { if (isDisposed()) { return; } if (event.getSource() instanceof TransactionalCommandStack) { final TransactionalCommandStack stack = ((TransactionalCommandStack) event.getSource()); if (stack.getMostRecentCommand() != null) { final Collection< ? > objects = stack.getMostRecentCommand().getAffectedObjects(); if (objects.isEmpty()) { updateAllDocs(); } else { for (final Object obj : objects) { final Resource resource = getResourceForObject(obj); if (resource != null) { updateDocument(resource); } } } } else { updateAllDocs(); } } } private Resource getResourceForObject(Object object) { object = AdapterFactoryEditingDomain.unwrap(object); if (object instanceof EObject) { return ((EObject) object).eResource(); } return null; } private void updateAllDocs() { for (Resource r : resourceToDocumentMap.keySet()) { updateDocument(r); } } /** * Updates the document that maps to the given resource. * @param resource The EMF Resource object which has been changed. This resource must be * within the resource to document map in order to pull up the corresponding document. */ private void updateDocument(final Resource resource) { if (this.resourceToDocumentMap.containsKey(resource)) { final IDocument document = this.resourceToDocumentMap.get(resource); // taken from org.eclipse.xsd.presentation.XSDEditor final ByteArrayOutputStream out = new ByteArrayOutputStream(); try { resource.save(out, null); final String newContent = out.toString(); final String oldContent = document.get(); int startIndex = 0; while (startIndex < newContent.length() && startIndex < oldContent.length() && newContent.charAt(startIndex) == oldContent.charAt(startIndex)) { ++startIndex; } int newEndIndex = newContent.length() - 1; int oldEndIndex = oldContent.length() - 1; while (newEndIndex >= startIndex && oldEndIndex >= startIndex && newContent.charAt(newEndIndex) == oldContent.charAt(oldEndIndex)) { --newEndIndex; --oldEndIndex; } final String replacement = newContent.substring(startIndex, newEndIndex + 1); final int length = oldEndIndex - startIndex + 1; // Only replace if there is actually a change if (!"".equals(replacement) || length != 0) { // Ignore this change in the document listener, since it originates with a change that is being // made in response to some other modification this.handledStructuredModelChange = true; document.replace(startIndex, length, replacement); } } catch (final Exception exception) { // SUPPRESS CHECKSTYLE Fallback // PASS } } } /** * @since 7.0 */ public List< ? > getPages() { if (this.pages == null) { return null; } return Collections.unmodifiableList((List< ? >) this.pages); } /** * @since 2.0 */ public abstract List<Object> getOutlineItems(); /** * @return * @since 2.1 */ public IdlLibrary getIdlLibrary() { return RedhawkUiActivator.getDefault().getIdlLibraryService().getLibrary(); } /** * @throws CoreException * @since 6.0 */ public void reloadIdlLibrary() { if (reloadLibraryJob == null) { reloadLibraryJob = new RefreshIdlLibraryJob(getIdlLibrary()); } reloadLibraryJob.schedule(); } /** * @throws CoreException * @since 3.0 */ public IdlLibrary loadIdlLibrary(final IProgressMonitor monitor) throws CoreException { IdlLibrary library = getIdlLibrary(); if (library != null) { IStatus status = library.getLoadStatus(); if (status == null) { library.load(monitor); } } return library; } /** * @return * @since 2.1 */ protected List<IPath> getDefaultIdlIncludePath() { return Collections.emptyList(); } /** * Sets the selection on this editor's viewer. * * @param collection the objects to select in the viewer * @since 5.0 */ public void setSelectionToViewer(final Collection< ? > collection) { // Make sure it's okay. // if (collection != null && !collection.isEmpty()) { final Collection< ? > theSelection = collection; final Runnable runnable = new Runnable() { @Override public void run() { // Try to select the items in the current content viewer of the editor. // final Viewer viewer = getViewer(); if (viewer != null) { final ISelection selection = ViewerUtil.itemsToSelection(viewer, theSelection); if (!selection.isEmpty()) { viewer.setSelection(selection, true); } } } }; getSite().getShell().getDisplay().asyncExec(runnable); } } /** * A tracked resource has been deleted. Sub-classes may override. * * @since 6.0 */ protected void resourceDeleted(final IResource resource) { // close the editor if the resource is deleted closeEditor(false); } /** * A tracked resource has been moved. Sub-classes may override. * * @since 6.0 */ protected void resourceMoved(final IResource from, final IResource to) { // reopen the editor on the new file if (to instanceof IFile) { setInput(new FileEditorInput((IFile) to)); } } /** * @since 8.0 */ public void reload() { reloading = true; try { if (getEditingDomain() != null) { for (final Resource r : getEditingDomain().getResourceSet().getResources().toArray(new Resource[0])) { if (r.getURI().isPlatformResource()) { try { WorkspaceSynchronizer.getFile(r).refreshLocal(IResource.DEPTH_ONE, null); } catch (CoreException e) { // PASS } } r.unload(); try { r.load(getEditingDomain().getResourceSet().getLoadOptions()); } catch (final IOException e) { // PASS } } getEditingDomain().getCommandStack().flush(); } } finally { reloading = false; } } /** * A tracked resource has been changed. Sub-classes may override. * * @param resource The resource who input has changed * @param delta The delta that describes that change that has occurred to the associated resource * @since 6.0 */ protected void resourceChanged(final IResource resource, final IResourceDelta delta) { // reload the model file for the resource which has been changed for (final Resource r : getEditingDomain().getResourceSet().getResources()) { final IFile file = WorkspaceSynchronizer.getFile(r); if (file != null && file.equals(resource)) { r.unload(); try { r.load(getEditingDomain().getResourceSet().getLoadOptions()); updateDocument(r); } catch (final IOException e) { // PASS } } } if (getEditingDomain() != null) { getEditingDomain().getCommandStack().flush(); } } /** * @since 6.0 */ public ResourceTracker getResourceTracker() { return this.resourceTracker; } /** * @since 8.0 */ public Map<Resource, IDocument> getResourceToDocumentMap() { return resourceToDocumentMap; } }